package com.hxm.appGenealogy.config;

import okhttp3.HttpUrl;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Random;


public class SignV3Utils {
    //V3主商户ID
    private static String merchantId = "1624602016";
    //微信商户平台APIv3证书序列号
    private static String certificateSerialNo = "1DE9380CD11FAB9D0D05AEAB16F7E7012252DB59";
    //私钥（不要把私钥文件暴露在公共场合，如上传到Github，写在客户端代码等。）
    private static String privateKey = "-----BEGIN PRIVATE KEY-----\n" +
            "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC1B/WnT6zDwj5l\n" +
            "yfzLwXYWBCrltaqkiK0GMow0K9gTS9I+bcmLKzUgsPHLqVPF1+dTeGc2cT1Iowye\n" +
            "1nB3wF/Xs1eToIHG+XrKoiFe3xNgvul/I3yeSZ+YGpQNtqp44nGMTdiUwtFz525V\n" +
            "KCjX/iepacexc9FZbiYi38l3QDfp51ulxFg05CKB25oG9MA4IXS4TYJ/ZB4EvxJw\n" +
            "qK1Meh1RnroMUkQrivI0TyMllOC+Sbw6rUjtIfZdJGBc+tGP6Iqr6ZqWO5BmGOVr\n" +
            "5sECSe80mNTtROBBweTDkpUQjEdy5AFEN1qFTQzgR/6bnaUWnfXhqQLZ7RtFSOe5\n" +
            "f7CcAdMbAgMBAAECggEAPSBX6Uu06VDAYvxmGKLVba+wkGncGbxwuAP/ZWpchn92\n" +
            "mU/W2uAXC1fT/VHKkKZLXNrt9usbp1gu3b9IsJbLhfjvnFB5IaeBt8QxAmjOkT9F\n" +
            "doGUBZqUgfaPgWXpf/HuJ1Lty6VQthMyJRzvVadi2wh1vkx+JvVTeTkZPOP5PUgo\n" +
            "UDXD+aHc44cXA2ZXTQWM4QnStdQFPLJaflQoeMqDJXocg4o7xuaTa5pcS7v99H5F\n" +
            "1MdYNO+E3yRkAZ9KAqrNVginpSXxcbxM+4laSIHMYJYCSon47jXA77xVHtxlQ+Tf\n" +
            "9h0eNMm7QrvFb0VTwfCAWxsIPDzUnhBObtXC+siI8QKBgQDxGtZxuYUTvjcy+UPJ\n" +
            "7GuimH3Pl91c7KZNURRS852g6/poBMAImCxFR/I180DvRqgWxpAE7kp17jPQ4a2j\n" +
            "bCLE7gHtXaz/HYUJcdSgeBrul1FMdnySSjTMZozTPfFO5MyFQvGxt9469uOn+FIw\n" +
            "mOCL5BTYgSKVUzAKOCB8EwZfcwKBgQDANwiNVImiqdJM205j3mC2V2bMXuqutwqh\n" +
            "jcYWnSxyxatUwJEGovLUdmPAzpqVkqcjOd1fbssr/6LFn0mq6xyvz03dfLNHd+tA\n" +
            "UAVnYCGMroMW2s0H2RhJOSJAh9IGKviQOhWQt8b+p0QPbt5xx/LzI9fNe65YDfdz\n" +
            "GKyonnWDuQKBgQDQ7sjWVEYWDcgXzBoKaW38wNiFhLy3Qfv7FD/ggmwef1/HtBYV\n" +
            "XIlAoFAsoFetAjW3RuqW20h7WahdYrPt4k9fCEFzSLIZgaM/w/zV8j6kc0xoTmU1\n" +
            "AEkwt81hYVQzYeI5uQFpWESkJD6z2GSg6Fnt4ACQfZdSf3wp3umHm5TyMQKBgQCB\n" +
            "iRUEWcJfkt6c2PadKxI2D/TBKf4yPDy33xltyAJaXog2F4gk1s+bCyXym8lln21v\n" +
            "ueFMHRhi0GZblBtLSiMNAEHTT+Rp95DcyJC7t/ckHb9OOaoO7ekF/7DrmByb932H\n" +
            "hP1fh9pdZ0/grrDOMRezb6ZRXlaCFPd741cIU7GSUQKBgQCvvw1cVtGH9brbp0yk\n" +
            "WPfNBsvI/AafHURZASBNReLq9VzaXD/4nMS9Hlojie+pBOJYE0uoF5prfyrVqow5\n" +
            "Sz9k/D/ehw2QgIIWBJxXaqNAlQvTvJYThY2kdjoXRJD1gRwm0Ge/dHUR3ewA2Iw5\n" +
            "zIaQn4RIUSrshoBiGYcfS4WyWw==\n" +
            "-----END PRIVATE KEY-----";

    /**
     * 使用方法
     * @param method 请求方法
     * @param url 请求url
     * @param body 请求内容
     * @return
     */
    public static HashMap<String, String> getSignMap(String method, String url, String body) throws InvalidKeySpecException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, SignatureException {
        String authorization = getSign(method, url, body);
        HashMap<String, String> headsMap = new HashMap<>();
        headsMap.put("Authorization", authorization);
        headsMap.put("Content-Type", "application/json");
        headsMap.put("Accept", "application/json");

        return headsMap;
    }

    public static String getSign(String method, String url, String body) throws NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException, UnsupportedEncodingException {
        return "WECHATPAY2-SHA256-RSA2048 " + getToken(method, HttpUrl.parse(url), body);
    }

    public static String getToken(String method, HttpUrl url, String body) throws UnsupportedEncodingException, SignatureException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
        String nonceStr = nonceString();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"));
        return "mchid=\"" + merchantId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + certificateSerialNo + "\","
                + "signature=\"" + signature + "\"";
    }

    public static String sign(byte[] message) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPKCS8PrivateKey(privateKey));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }

        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }


    private static PrivateKey getPKCS8PrivateKey(String strPk) throws NoSuchAlgorithmException, InvalidKeySpecException {
        String realPK = strPk.replaceAll("-----END PRIVATE KEY-----", "")
                .replaceAll("-----BEGIN PRIVATE KEY-----", "")
                .replaceAll("\n", "");

        byte[] b1 = Base64.getDecoder().decode(realPK);

        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1);

        KeyFactory kf = KeyFactory.getInstance("RSA");

        return kf.generatePrivate(spec);
    }

    public static String nonceString() {

        String currTime = String.format("%d", (long) System.currentTimeMillis() / 1000);

        String strTime = currTime.substring(8, currTime.length());

        Random random = new Random();
        int num = (int) (random.nextDouble() * (1000000 - 100000) + 100000);
        String code = String.format("%06d", num);

        String nonce_str = currTime.substring(2) + code;
        return nonce_str;

    }
}

